﻿using System;

namespace Util.ActionUtils
{
    // V 1.0.3 - 2021-09-28 09:42:19
    // 因为很多情况适用, 故从 Util.HowesDOMO 项目中提取出来。
    //
    // V 1.0.2 - 2020-2-19 16:04:06
    // 改进代码, 适合与 WinForm 与 WPF
    //
    // V 1.0.0 - 2020-2-14 18:03:42
    // 首次创建

    /// <summary>
    /// <para>预先设定一个执行不应周期，当调用动作的时刻大于等于执行不应周期则执行Action委托，然后进入下一个新周期</para>
    /// </summary>   
    public class ThrottleAction
    {
        System.Timers.Timer mThrottleTimer;

        ///// <summary>
        /////  ( WPF适用 ) 即刻执行，在指定执行不应周期内再次调用无效
        ///// </summary>
        ///// <param name="interval">执行不应周期（单位毫秒）</param>
        ///// <param name="action">定义执行逻辑</param>
        ///// <param name="dispatcher">通常设置 null 或 Application.Current.Dispatcher</param>
        //public void Throttle(double interval, Action action, System.Windows.Threading.Dispatcher dispatcher = null)
        //{
        //    System.Threading.Monitor.Enter(this);
        //    bool needExit = true;
        //    try
        //    {
        //        if (mThrottleTimer == null)
        //        {
        //            mThrottleTimer = new System.Timers.Timer(interval);
        //            mThrottleTimer.AutoReset = false;
        //            mThrottleTimer.Elapsed += (o, e) =>
        //            {
        //                mThrottleTimer.Stop();
        //                mThrottleTimer.Close();
        //                mThrottleTimer = null;
        //            };
        //            mThrottleTimer.Start();

        //            System.Threading.Monitor.Exit(this); // 已保证Timer成功创建, 可以将锁释放
        //            needExit = false;

        //            if (dispatcher != null && dispatcher.Thread.IsBackground == false) //这个过程不能锁
        //            {
        //                dispatcher.Invoke(action, null);
        //            }
        //            else
        //            {
        //                action();
        //            }
        //        }
        //    }
        //    finally
        //    {
        //        if (needExit)
        //        {
        //            System.Threading.Monitor.Exit(this);
        //        }
        //    }
        //}

        /// <summary>
        /// ( Winform 适用 ) 即刻执行，在指定执行不应周期内再次调用无效
        /// </summary>
        /// <param name="interval">执行不应周期（单位毫秒）</param>
        /// <param name="action">定义执行逻辑</param>
        /// <param name="syncInvoke">同步对象(一般为UI控件)，如不需同步可传null</param>
        public void Throttle(double interval, Action action, System.ComponentModel.ISynchronizeInvoke syncInvoke)
        {
            System.Threading.Monitor.Enter(this);
            bool needExit = true;
            try
            {
                if (mThrottleTimer == null)
                {
                    mThrottleTimer = new System.Timers.Timer(interval);
                    mThrottleTimer.AutoReset = false;
                    mThrottleTimer.Elapsed += (o, e) =>
                    {
                        mThrottleTimer.Stop();
                        mThrottleTimer.Close();
                        mThrottleTimer = null;
                    };

                    mThrottleTimer.Start();

                    System.Threading.Monitor.Exit(this); // 已保证Timer成功创建, 可以将锁释放
                    needExit = false;

                    if (syncInvoke != null && syncInvoke.InvokeRequired == true) //这个过程不能锁
                    {
                        syncInvoke.Invoke(action, null);
                    }
                    else
                    {
                        action();
                    }
                }
            }
            finally
            {
                if (needExit)
                {
                    System.Threading.Monitor.Exit(this);
                }
            }
        }
    }
}
